// i.d(t, { M_: () => CameraData, rw: () => u })
import n from "../math/63560"
import Data from "../object/Data"

import l from "../math/69626"
import Matrix from "../three/Matrix"
import d from "../math/7170"
import CameraPoseData from "../object/CameraPoseData"
import CameraTransition from "../object/CameraTransition"

const isSame = (e: THREE.Vector3 | THREE.Quaternion | THREE.Matrix4 | Matrix, t: THREE.Vector3 | THREE.Quaternion | THREE.Matrix4 | Matrix) =>
  e && t ? e.equals(t) : e === t
export const copyData = (e, t, i = !0) => {
  t.position = copyVal(e.position, t.position, i)
  t.rotation = copyVal(e.rotation, t.rotation, i)
  t.projection = copyVal(e.projection, t.projection, i)
  t.focalDistance = e.focalDistance
}
const copyVal = (e, t, i = !0) => (e && !t ? (t = e.clone()) : e && t ? t.copy(e) : i && (t = void 0), t)
export default class CameraData extends Data {
  pose: CameraPoseData
  protected _width: number
  protected _height: number
  protected _baseProjection: Matrix
  transition: CameraTransition
  protected _orthoMatrix: Matrix
  protected _lastOrthoZoom: number
  protected _perspectiveMatrix: Matrix
  protected _baseFovY: number
  constructor(width: number, height: number) {
    super()
    this._width = width
    this._height = height
    this.name = "camera-data"
    this._baseProjection = new Matrix()
    this._orthoMatrix = new Matrix()
    this._lastOrthoZoom = 1
    this._perspectiveMatrix = new Matrix()
    this.pose = new CameraPoseData(width / height)
    this.transition = new CameraTransition()
    this.setCameraDimensions(width, height)
    this._baseFovY = d.Ue * n.oR.fov
  }
  setCameraDimensions(e: number, t: number) {
    if (void 0 === e || void 0 === t) return
    this._width = e
    this._height = t
    const i = e / t
    const s = this.isOrtho()
      ? n.aH(e, t, t / (2 * this.orthoZoom()), this._orthoMatrix)
      : this._perspectiveMatrix.makePerspectiveFov(d.MN * this.fovY(), i, n.oR.near, n.oR.far)
    if ((this.pose.projection.copy(s), this.transition.active && this.transition.to.projection))
      if (l.Pp(this.transition.to.projection)) {
        const i = l.S3(this.transition.to.projection)
        this.transition.to.projection.copy(n.aH(e, t, t / (2 * i)))
      } else {
        const e = 2 * d.MN * Math.atan(1 / this.transition.to.projection.elements[5])
        this.transition.to.projection.makePerspectiveFov(e, i, n.oR.near, n.oR.far)
      }
    this.pose.commit()
  }
  setBaseProjection(e: Matrix) {
    this._baseProjection = e
  }
  get width() {
    return this._width
  }
  get height() {
    return this._height
  }
  get baseFovY() {
    return this._baseFovY
  }
  aspect() {
    return this.pose.aspect()
  }
  fovY() {
    return this.pose.fovY()
  }
  fovX() {
    return this.pose.fovX()
  }
  isOrtho() {
    return this.pose.isOrtho()
  }
  baseZoom() {
    return this.pose.projection.elements[0] / 2
  }
  defaultZoom() {
    return l.Pp(this._baseProjection) ? l.S3(this._baseProjection) : this.perspectiveZoom()
  }
  zoom() {
    return this.isOrtho() ? this.orthoZoom() : this.perspectiveZoom()
  }
  orthoZoom() {
    const e = l.S3(this.pose.projection)
    return isNaN(e) ? this._lastOrthoZoom : ((this._lastOrthoZoom = e), this.commit(), e)
  }
  perspectiveZoom() {
    return this.baseFovY / this.fovY()
  }
  copyTransition(e: CameraTransition) {
    this.transition.active = e.active
    this.transition.activeInternal = e.activeInternal
    this.transition.type = e.type
    this.transition.startTime = e.startTime
    this.transition.duration = e.duration
    this.transition.rotationDelay = e.rotationDelay
    this.transition.rotationDuration = e.rotationDuration
    this.transition.matrixDelay = e.matrixDelay
    this.transition.matrixDuration = e.matrixDuration
    e.progress && this.transition.progress.copy(e.progress)
    e.blackoutProgress && this.transition.blackoutProgress.copy(e.blackoutProgress)
    e.from && copyData(e.from, this.transition.from)
    e.to && copyData(e.to, this.transition.to)
    this.transition.promise = e.promise
  }
  canTransition() {
    return !this.transition.active
  }
  clone() {
    const e = new CameraData(this.width, this.height)
    e.copy(this)
    return e
  }
  copy(e: CameraData) {
    this.pose.position.copy(e.pose.position)
    this.pose.rotation.copy(e.pose.rotation)
    this.pose.focalDistance = e.pose.focalDistance
    this.pose.projection.copy(e.pose.projection)
    this.pose.commit()
    this._baseFovY = e.baseFovY
    this.copyTransition(e.transition)
    this.transition.commit()
    this._width = e.width
    this._height = e.height
  }
  shallowIsEqual(e) {
    return (
      this.pose.position.equals(e.pose.position) &&
      this.pose.rotation.equals(e.pose.rotation) &&
      this.pose.projection.equals(e.pose.projection) &&
      this.pose.focalDistance === e.pose.focalDistance &&
      this.baseFovY === e.baseFovY
    )
  }
  isEqual(e) {
    return this.shallowIsEqual(e) && this.transitionIsEqual(e.transition)
  }
  transitionIsEqual(e: CameraTransition) {
    return (
      this.transition.active === e.active &&
      this.transition.type === e.type &&
      this.transition.progress.equals(e.progress) &&
      this.transition.blackoutProgress.equals(e.blackoutProgress) &&
      this.transition.rotationDelay === e.rotationDelay &&
      this.transition.rotationDuration === e.rotationDuration &&
      this.transition.matrixDelay === e.matrixDelay &&
      this.transition.matrixDuration === e.matrixDuration &&
      this.transition.activeInternal === e.activeInternal &&
      isSame(this.transition.from.position, e.from.position) &&
      isSame(this.transition.from.rotation, e.from.rotation) &&
      isSame(this.transition.from.projection, e.from.projection) &&
      isSame(this.transition.to.position, e.to.position) &&
      isSame(this.transition.to.rotation, e.to.rotation) &&
      isSame(this.transition.to.projection, e.to.projection) &&
      this.transition.startTime === e.startTime &&
      this.transition.duration === e.duration
    )
  }
}
